<?php

namespace app\common\services\token\driver;

use app\common\services\token\Driver;
use think\facade\Cache as C;
use think\facade\Config;

/**
 * Token操作类
 */
class Cache extends Driver
{

    protected $options = [
        'expire'       => 0,
        'token_prefix' => 'user_token_',
        'user_prefix'  => 'user_keys_',
        'tag'          => 'user_token',
    ];

    /**
     * 构造函数
     * @param array $options 缓存参数
     * @throws \BadFunctionCallException
     * @access public
     */
    public function __construct($options = [])
    {
    }

    /**
     * 获取加密后的Token
     * @param string $token Token标识
     * @return string
     */
    protected function getEncryptedToken($token)
    {
        $config = Config::get('app.token');
        return $this->options['token_prefix'] . hash_hmac($config['encryption'], $token, $config['key']);
    }

    /**
     * 获取会员的key
     * @param $uid
     * @return string
     */
    protected function getUserKey($uid)
    {
        return $this->options['user_prefix'] . $uid;
    }

    /**
     * 存储Token
     * @param string $token Token
     * @param int $uid 会员ID
     * @param int $expire 过期时长,0表示无限,单位秒
     * @return bool
     */
    public function set($token, $uid, $expire = 0)
    {
        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }
        if ($expire instanceof \DateTime) {
            $expire = $expire->getTimestamp() - time();
        }
        $key = $this->getEncryptedToken($token);
        $result = C::tag($this->options['tag'])->set($key, $uid, $expire);
        C::push($this->options['user_prefix'] . $uid, $key);
        return $result;
    }

    /**
     * 获取Token内的信息
     * @param string $token
     * @return  array
     */
    public function get($token)
    {
        $key = $this->getEncryptedToken($token);
        $value = C::get($key);
        if (is_null($value) || false === $value) {
            return [];
        }
        return $value;
    }

    /**
     * 判断Token是否可用
     * @param string $token Token
     * @param int $uid 会员ID
     * @return  boolean
     */
    public function check($token, $uid)
    {
        $data = self::get($token);
        return $data && $data['uid'] == $uid ? true : false;
    }

    /**
     * 删除Token
     * @param string $token
     * @return  boolean
     */
    public function delete($token)
    {
        $key = $this->getEncryptedToken($token);
        C::delete($key);
        return true;
    }

    /**
     * 删除指定用户的所有Token
     * @param int $uid
     * @return  boolean
     */
    public function clear($uid)
    {
        $keys = C::get($this->options['user_prefix'] . $uid);
        foreach ($keys as $key) {
            C::delete($key);
        }
        return true;
    }
}
